###################################################
# sequence 序列
# 序列分为两类：
#   可变序列list
#   不可变序列 字符串str 元组 tuple

# list 列表
my_list = [] # 空列表
my_list = [1,2,3] # 三个元素的列表
my_list2 = [1,2,3]
# == != 比较的是值， is  is not比较的是地址
print(my_list == my_list2)

# 列表元素可以是任意类型的数据，包括函数，最后一个print为内建函数
my_list = [1, 2 , 3, True, 'hello', None, [4,5,6], print]
# len(x) 获取列表的长度
print(my_list, len(my_list), type(my_list))

# 通过下标访问， 访问第一个元素和最后一个元素, 从后访问，下标为负数，-1代表倒数第一个
print(my_list[0], my_list[-1])

# 切片, 获取列表的子列表,对原列表没影响，切片的两个值，代表起始位置和结束位置，但是获取到的元素包含起始位置的元素不包含结束位置的元素
# 起始、结束位置可以省略，如果省略就代表从头或者到最后
print(my_list[1:3], my_list[:2], my_list[5:])
# 对于起始位置和结束位置都省了的，相当于原列表的一个副本
print(my_list[:])
# 切片的步长，第三个值代表步长，隔几个取值，默认1, 下面相当于取第1和3个元素，因为步长为2，取第一个元素后，跳过一个再取
print(my_list[0:4:2])
# 当步长为负数时，代表从后往前取
print(my_list[::-2])

print('-'*66)

# +操作将两个列表拼接, *将列表重复多少次
a = [1,2,3]
b = [4,5,6]
print(a + b, a * 2)
print(5 in b, 5 in a, 5 not in a, max(a), max(b))   
print('-'*66)

# 列表方法 index() count() append() 
a = ['a', 'b', 'c'] * 2
# 获取第一个a元素的下标, 从下标3开始查找a的下标，计算a元素出现的次数
print(a.index('a'), a.index('a', 3), a.count('a')) 
a.append('append1') # append一个元素, 不能通过索引下标增加一个下标不存在的元素
a.insert(1, 'insert1') # 向某个位置插入一个元素
a.extend(['hello,world']) # 将另一个列表加入到本列表后面，相当于 + 操作
# 清空序列
b.clear()
print(a)
# 弹出一个元素, 默认弹出列表最后一个，可以指定弹出下标
print('pop =>',a.pop(), '| pop 0 =>', a.pop(0))
# 删除指定值, 如果重复，只删除第一个
a.remove('a')
# 列表反转
a.reverse()
# 列表排序, reverse默认升序，可以设置true降序排列
a.sort(reverse=True)

print('-'*66)
# 列表修改 根据下标，或者切片
a[0] = 'abc'
print(a)
del a[0]
print(a)
# 切片修改，赋值必须是序列, 赋值的列表个数可以不等于切片元素个数
a[0:2] = ['o', 'p','hello']
# 向0位置插入一个元素
a[0:0] = ['world']
# 切片设置步长后，赋值的列表元素个数必须和切片元素个数相同, 将设置步长后的切片匹配到的元素赋值为指定值
a[0:3:2] = ['aaa', 'bbb']
# 删除0、1两个元素，默认步长为1
del a[0:2] 
# 删除步长为2匹配到的切片元素
del a[::2]
# 赋空值也可以删除元素, 相当于删除第一个元素外的元素
a[1:] = []

print(a)
print('-'*66)

# 循环遍历列表所有数据
# for 变量 in 序列 :
#       代码块
for d in my_list :
    print(d)
else :
    print('for complete')

print('-'*66)
# 字符串是一种特殊的list
a = 'hello'
print(a[3], a[:2], a[3:], 'he' in a)
# 将不可变列表str转换为可变列表list
alist = list(a)
print(alist)

# range(起始位置默认0，结束位置，步长默认1) 函数 生成迭代序列
print(list(range(5))) # 生成5个数，0-4
print(list(range(5, 10))) # 生成5-9
print(list(range(5, 10, 2))) # 步长2，生成5，7，9
print(list(range(10, 5, -1))) # 倒序
for i in range(10) :
    print(i, end='\t')

print()    
for s in 'hello' :
    print(s, end = '\t')

############list 练习############
users = []
while False :
    print('+' * 22, 'User Manager System', '+' * 22)
    print('\t 1. add user')
    print('\t 2. list user')
    print('\t 3. del user')
    print('\t 4. exit')
    opt = input('choose option\'s no please: ')
    if opt == '1' :
        username = input('input username: ')
        addr = input('input user addr: ')
        users.append([username, addr])
        print(f'{username} add success!')
    elif opt == '2' :
        for i in range(len(users)) :
            print(i, users[i])
    elif opt == '3' :
        username = input('input username for delete: ')
        flag = False
        for user in users :
            if username in user :
                users.remove(user)
                print(f'{username} delete success!')
                flag = True
        if flag == False :
            print(f'{username} not found!')
    elif opt == '4' :
        print('bye bye')
        break
    else :
        print('input error, retry please!')


# tuple 元组 不可变序列， 使用方式与list相似，但是不支持修改
print()
print('+' * 66)
my_tuple = () # 空元组
my_tuple = (1,) # 元组如果只有一个元素，必须带有逗号，否则就变成了简单的变量赋值，不是元组了
my_tuple = (1,2,3)
my_tuple = 4,5,6,7 # 当元组不为空时，可以省略括号
a,b,c,d = my_tuple # 将元组中的4个元素分别赋值给4个变量，称为解包/解构，list/str也可以使用
# 对于python中的解包操作可以很方便的实现两个数值的交换，
a, b = b, a # b,a相当于一个元组，实现将a,b值互换的效果
# 如果不需要将元组中的所有元素都进行解包，只取前两个. *变量接受其他元素， * 号同时只能出现一个
a, b, *other = my_tuple # 前两个变量值赋值给a,b, 元组剩下的元素作为一个序列赋值给other, 必须有other接收其他值，否则变量个数不匹配元组个数会报错
a, *other, b = my_tuple # 相当于第一个元素给a,最后一个元素给b,其他的给other
*other, a, b = my_tuple # 相当于倒数前两个给a,b，其他的给other
print('tuple =>', my_tuple, type(my_tuple))


####################### 字典 dict(map) #######################
# 相当java中的map, k-v数据结构
# 变量 = {key:value, key:value ..}
# key 可以是任意不可变对象(int str bool tuple..)， value可以是任意对象
d = {} # 空字典
d = {'key1':'hello', 'key2':'world'} # 常用
# 其他形式的创建字典 
d = dict() # 通过构造函数
d = dict(key1 = 'hello', key2 = 'world') # 创建字典，此方式key都是字符串
d = dict([('key1','value1'),('key2', 'value2')]) # 通过双值子序列创建dict
# d[key]取值时不存在key会报错，key in d 判断是否存在key
print(d, type(d), d['key1'], len(d), 'key1' not in d)
# get(key[, def]), 获取值，不存在不报错，可指定默认值
print(d.get('key3', 'default value'))
d['key1'] = 'key1value' # 修改
d['key3'] = 'value3' # 新增一个k-v

# putIfAbsent, 添加key，如果存在不替换，返回已存在的值，否则设置新值
d.setdefault('key1', 'value1')

# update(dict) 将d2中的数据合并到d1中，如果不存在添加，存在则更新d1
d1 = {'a':'a', 'b':'b'}
d2 = {'d':'d', 'b':'c'}
d1.update(d2)
del d1['a'] # 删除key=a的元素
print(d1.pop('dd', 'def value')) # 弹出key=d的元素，如果不指定默认值， key不存在报错
print(d1.popitem()) # 随机弹出一个元素, 字典不可以为空
print(d1)
d3 = d2.copy() # 浅复制，如果value不是一个基本对象，则该对象不会被复制
d2.clear() # 清空字典
# 获取所有key， values
print(list(d1), d1.keys(), d1.values())
for k in d1.keys():
    print(k, d1.get(k))

# items() 获取kv双值tuple子序列
for item in d1.items():
    print(item)    
for k,v in d1.items():
    print(k,v)

# Set集合，无序, 不可重复, 只能存储不可变对象(int bool tuple str)
s = {} # 空set
s = set() # 空set
s = set('a')
s = set(d) # 将字典中的key创建一个set
s = {'a','b', 2} # 
s.add('ok') # 添加元素
s.update({1,2,3}) # 与dict.update一样，并集，也可以与set、list、tuple、dict并集
s.remove('a') # 删除指定元素
print(s.pop()) # 随机弹出一个元素
print(s, type(s))
# set无法通过索引访问，
print('a' in s, len(s))
s.clear() # 清空

# set集合运算
s1 = {1,2,3,4}
s2 = {3,5,6,8}
print(s1 & s2) # 交集
print(s1 | s2) # 并集
print(s1 - s2) # 差集
print(s1 ^ s2) # 异或，非共有的部分
print(s1 <= s2) # s1是否是s2的子集
print(s1 < s2) # 真子集，s2中包含s1的所有元素，并且还有s1中没有的元素，则s1是s2的真子集
